VOLATILIDAD

En la administración y cuantificación de riesgos, la volatilidad \(σ_{i,t}\) juega un papel central para medir pérdidas potenciales, ya que indica cuál es la fluctuación de la rentabilidad o del precio de un activo con respecto a su cotización media histórica. Este concepto es de alta utilidad, puesto que a mayor volatilidad de un activo, mayor es el riesgo de que la rentabilidad sea distinta a la esperada.

Para calcular la volatilidad y con ello poder comparar las volatilidades de un activo con la de otros se utiliza la desviación estándar, pues ofrece información sobre la volatilidad que ha tenido un activo en el pasado de forma resumida.

Incialmente, la volatilidad será la diferencia entre lo que se espera \(E_{r,t}\) y lo que realmente se tiene \(r_{i,t}\). Una primera aproximación de volatilidad se da por la ecuación:

\[\begin{align} σ_{i,t} = \sqrt{\frac{\sum(r_{i,t}-E_{r,t})^2}{t-1}} \end{align}\]

La cual otorga a cada una una de las observaciones la misma ponderación en el tiempo, esto se traduce en que una observación antigüa tiene el mismo peso que una reciente.

Teniendo en cuenta este fenómeno variante se considerarán 3 tipos de volatilidad:

Volatilidad convencional o fija en el tiempo

La volatilidad convencional o fija en el tiempo es la más empleada debido a su simplicidad y facil implementación.

Ésta se interprea como una medida de dispersión para entender cuánto varian los datos en relación con la media del conjunto de datos. Esto permite reconocer la variabilidad dentro de los datos, lo cual resulta escencial para comprender las inconsistencias de las mediciones, de esta forma al comparar desviaciones estándar es posible evaluar la variabilidad de la siguiente forma:

  • Baja desviación estándar: los datos están cercanos a la media, por lo que hay poca variabilidad.
  • Mayor desviación estándar: los datos están más dispersos, por lo que hay una mayor variabilidad en las mediciones.

Como se mencionó anteriormente, la desviación estándar posee algunas limitaciones como:

  1. Otorga el mismo peso a cada una de las observaciones. Lo que resulta poco eficiente si se busca un modelo sensible a nueva información.
  2. Es sensible a valores extremos, lo que puede distorsionar la percepción de la variabilidad de los datos.
  3. La interpretación es más efectiva en distribuciones normales, ya que en distribuciones sesgadas su utilidad puede ser limitada.

Volatilidad con suavizamiento exponencial

A diferencia de la volatilidad convencional, la volatilidad exponencial da un mayor peso a las observaciones recientes y menos a las antiguas. De esta forma, aplicando un peso \(\lambda\) y utilizando la fórmula para el promedio movil ponderado, se tendrá la siguiente formulación:

\[\begin{align} PME = \frac{\sum_{n=1}^{t} r_{i,t-n} * \lambda^{n-1} }{\sum_{n=0}^{t-2} \lambda^n} \end{align}\]

donde \(\lambda\) es el factor de suavizamiento y \(r_{i,t}\) es la variación porcentual de los precios de cierre de los activos estudiados en el rezago t-n. \(\lambda \epsilon [0,1]\) permitiendo que las observaciones más lejanas tiendan a 0, ie, mientras n crece.

Aplicando la formulación anterior, para una serie de rendimientos al cuadrado, se llegará a la varianza con suavizamiento exponencial \(\hat{σ_{i,t}}\) dada por:

\[\begin{align} \hat{σ_{i,t}}= (1-\lambda) \sum_{n = 1}^{\infty} \lambda^{n-1} r_{i,t-1}^{2} \end{align}\]

Otra forma de calcular la varianza con suavizamiento exponencial es implementando la siguiente fórmula recursiva:

\[\begin{align} \hat{σ_{i,t}}= \sqrt{(1-\lambda) r_{i,t-1}^{2} + \lambda \hat{σ_{i,t-1}}^{2}} \end{align}\]

Notese que en todos estos cálculos, el valor de \(\lambda\) es crucial para el resultado, por lo que se debe seleccionar el valor adecuado u óptimo que permita evitar la sobre o subestimación de la pérdida potencial.

Nótese que al aplicar la volatilidad con suavizamiento exponencial permite implementar un análisis donde los datos más recientes son los que más información aportan, sin embargo, el hecho de incorporar este efecto, genera una alta dependencia sobre un valor \(\lambda\) que puede ser subjetiva y afectar los resultados.

Volatilidad Generalizada Autorregresiva con Heteroscedasticidad (GARCH)

A partir de la volatilidad con suavizamiento exponencial es posible concluir que la volatilidad no necesariamente tiene que ser constante en el tiempo, más aún, este valor puede estar oscilando cerca de un valor de largo plazo, \(\omega = σ_{0}\).

En este sentido, los modelos GARCH permiten que el valor de \(\hat{σ_{i,t}}\) parta de una magnitud inercial o fija:

\[\begin{align} \hat{σ_{GARCH,i,t}}= \omega + \beta_{1} r_{i,t-1} ^{2} + \gamma_{1} \hat{σ_{i,t-1}}^{2} \end{align}\]

Notese la similitud con el modelo de suavizamiento exponencial, con \(\beta_{1}=1-\lambda\) y \(\gamma_{1}=\lambda\), la diferencia radica en la introducción de un valor inercial o fijo de la volatilidad \(\alpha\). Estos coeficientes se estiman por medio de métodos numéricos o de optimización.

Así, el modelo \(\hat{σ_{GARCH,i,t}}\) es el mejor, puesto que permite que la volatilidad cambie en el tiempo y se hagan pronósticos de volatilidad en t+n.

Este modelo cumple:

  • \(\beta_{1}\),\(\gamma_{1}\) \(\epsilon\) \([0,1]\)
  • \(\beta_{1} + \gamma_{1} < 1\), para que el modelo sea estable y converja a un valor de volatilidad de largo plazo \(\omega\).
  • \(\omega = (1-\beta_{1} + \gamma_{1})^{-1}\)

El modelo GARCH también tiene una forma recursiva, dada por:

\[\begin{align} \hat{σ_{GARCH,i,t}}= \alpha + \sum_{p=1}^{P} \beta_{p} r_{i,t-p} ^{2} + \sum_{q=1}^{Q} \gamma_{q} \hat{σ_{i,t-q}}^{2} \end{align}\]

Para determinar el mejor modelo con P y Q rezagos se utiliza el criterio de información de Akaike (AIC), Bayesiano (BIC) para determinar el mejor modelo.

Conglomerado de volatilidades

El conglomerado de volatilidades o volatility clustering es un fenómeno de los mercados financieros y series de precios de los activos. Este describe la tendencia de los mercados a experimentar periodos de alta volatilidad seguidos de otros periodos de alta volatilidad, así como periodods de baja volatilidad seguidos de periodos de baja volatilidad, esto es, la volatilidad tiende a agruparse en el tiempo creando conglomerados o clusters con comportamiento similar.

Si bien, los rendimientos en sí mismos no están correlacionados, los rendimientos absolutos \(|r_{t}|\) o sus cuadrados muestran una correlación positiva, significativa que decae lentamente. Las observaciones de este tipo de series temporales va contra los modelos simples llevando al uso de modelos GARCH y de volatilidad estocástica que revierten la media en la predición.

Los modelos GARCH están diseñados para capturar la heterocedasticidad condicional, la cual es la principal característica de los conglomerados, mediante los siguientes procesos:

  • Dado que la volatiidad alta persiste en el tiempo, los periodos de alta volatilidad no desaparecen de inmediato, más aún, estos se prolongan.
  • El modelo considera las volatilidades recientes y pasadas. Si la volatilidad fue alta en el pasado, probablemente lo siga siendo.

Resumen de volatilidades

A continuación se presenta una tabla que compara los diversos métodos para el cálculo de la volatilidad.

Método Ventajas Desventajas
Desviación estándar o fija en el tiempo Es el más simple y proporciona un cálculo fijo en el tiempo. Da el mismo peso a todos los datos, se ve afectado por datos atípicos.
Desviación con suavizamiento exponencial Asigna mayor peso a las observaciones recientes No necesariamente la distribución es exponencial, introduce un termino de alta dependencia \(\lambda\)
Modelo GARCH Usa información pasada para mejorar el proceso, capta el fenómeno de aglomerado de volatilidades. Es más complejo que los otros modelos, y puede ser más pesado en términos computacionales.

Ejemplo práctico

Para ilustrar mejor el cálculo de volatilidades anteriormente explicado se hará el calculo cuantitativo de estas en el fondo QQQ desde 20/11/2023 hasta 20/11/2024.

La volatilidad convencional será:

sigma_fija=sd(rendimientos)
sigma_fija
## [1] 1.097977

La volatilidad con suavizamiento exponencial al 0.95 y 0.98:

# Volatilidad con suavizamiento exponencial con lambda=0.95:
sigma95Lambda=funEWSigma(rendimientos,0.95)

# Volatilidad con suavizamiento exponencial con lambda=0.98:
sigma98Lambda=funEWSigma(rendimientos,0.98)

La volatilidad GARCH con función gaussiana:

# Se crea el objeto spec del modelo GARCH:
modeloGARCH=ugarchspec(variance.model = list(model = "sGARCH", 
                       garchOrder = c(1, 1)), 
                       mean.model = list(armaOrder = c(0, 0), 
                                         include.mean = FALSE), 
                       distribution.model = "norm")
# Se ajusta el modelo GARCH:
ajusteGARCH_NORM=ugarchfit(spec=modeloGARCH, data=rendimientos)

coeficientesGARCH=data.frame(coeficientes=ajusteGARCH_NORM@fit$coef,
                             errores=ajusteGARCH_NORM@fit$robust.se.coef,
                             valoresT=ajusteGARCH_NORM@fit$tval,
        Pvalues=2*(1-pt(abs(ajusteGARCH_NORM@fit$tval),df=length(rendimientos)-3))
)

# Desviación estándar GARCH:
sigmaGARCH_GAUSS=funGARCH(rendimientos,model="sGARCH",LLF="norm",garchOrder=c(1,1),arma=c(0,0),include.mean=FALSE)

sigmaGARCH_GAUSS
## [1] 1.185836

La volatilidad GARCH con función t-Student:

# Se crea el objeto spec del modelo GARCH:
modeloGARCH=ugarchspec(variance.model = list(model = "sGARCH", 
                       garchOrder = c(1, 1)), 
                       mean.model = list(armaOrder = c(0, 0), 
                                         include.mean = FALSE), 
                       distribution.model = "std")
# Se ajusta el modelo GARCH:
ajusteGARCH_STD=ugarchfit(spec=modeloGARCH, data=rendimientos)

coeficientesGARCH=data.frame(coeficientes=ajusteGARCH_STD@fit$coef,
                             errores=ajusteGARCH_STD@fit$robust.se.coef,
                             valoresT=ajusteGARCH_STD@fit$tval,
        Pvalues=2*(1-pt(abs(ajusteGARCH_STD@fit$tval),df=length(rendimientos)-3))
)

# Desviación estándar GARCH:
sigmaGARCH_std=funGARCH(rendimientos,model="sGARCH",LLF="std",garchOrder=c(1,1),arma=c(0,0),include.mean=FALSE)

sigmaGARCH_std
## [1] 1.198438

La volatilidad GARCH con función GED:

# Se crea el objeto spec del modelo GARCH:
modeloGARCH=ugarchspec(variance.model = list(model = "sGARCH", 
                       garchOrder = c(1, 1)), 
                       mean.model = list(armaOrder = c(0, 0), 
                                         include.mean = FALSE), 
                       distribution.model = "ged")
# Se ajusta el modelo GARCH:
ajusteGARCH_GED=ugarchfit(spec=modeloGARCH, data=rendimientos)

coeficientesGARCH=data.frame(coeficientes=ajusteGARCH_GED@fit$coef,
                             errores=ajusteGARCH_GED@fit$robust.se.coef,
                             valoresT=ajusteGARCH_GED@fit$tval,
        Pvalues=2*(1-pt(abs(ajusteGARCH_GED@fit$tval),df=length(rendimientos)-3))
)

# Desviación estándar GARCH:
sigmaGARCH_GED=funGARCH(rendimientos,model="sGARCH",LLF="ged",garchOrder=c(1,1),arma=c(0,0),include.mean=FALSE)

sigmaGARCH_GED
## [1] 1.189749

Calculo de volatilidad con GJR-GARCH (asimétrico) con función de verosimilitud gaussiana:

# Se especifica el modelo GJR-GARCH
gjr_spec <- ugarchspec(
  mean.model = list(armaOrder = c(0, 0)), 
  variance.model = list(model = "gjrGARCH", garchOrder = c(1, 1)),  
  distribution.model = "norm"  
)

gjr_fit_norm <- ugarchfit(spec = gjr_spec, data = rendimientos)

var_cond_norm <- sigma(gjr_fit_norm)^2  

desviacion_estandar_norm <- sqrt(var_cond_norm) 

Calculo de volatilidad con GJR-GARCH (asimétrico) con función de verosimilitud t-Student:

# Se especifica el modelo GJR-GARCH
gjr_spec <- ugarchspec(
  mean.model = list(armaOrder = c(0, 0)),  
  variance.model = list(model = "gjrGARCH", garchOrder = c(1, 1)),  
  distribution.model = "std"  
)

gjr_fit_std <- ugarchfit(spec = gjr_spec, data = rendimientos)

var_cond_std <- sigma(gjr_fit_std)^2  

desviacion_estandar_std <- sqrt(var_cond_std)  

Calculo de volatilidad con GJR-GARCH (asimétrico) con función de verosimilitud GED:

# Se especifica el modelo GJR-GARCH
gjr_spec <- ugarchspec(
  mean.model = list(armaOrder = c(0, 0)),  
  variance.model = list(model = "gjrGARCH", garchOrder = c(1, 1)),  
  distribution.model = "ged"  
)

gjr_fit_ged <- ugarchfit(spec = gjr_spec, data = rendimientos)

var_cond_ged <- sigma(gjr_fit_ged)^2  

desviacion_estandar_ged <- sqrt(var_cond_ged)  

Se utiliza el criterio Akaike, con la función AIC:

Ahora para futuras aplicaciones de backtesting, se utilizarán los datos desde el 20 de noviembre de 2019 con periodicidad diaria con ventana movil de 250 días.

tickerV=c("QQQ")
hastaD=as.Date("2024-11-20")
deD=as.Date("2019-11-20")
per="D"
paridadFX="USDMXN=X"
convertirFX=c(FALSE)
Datos=historico_multiples_precios(tickers=tickerV,de=deD,hasta=hastaD,periodicidad=per,fxRate=paridadFX,whichToFX=convertirFX)
## [1] "Extrayendo RIC 1 de 1 (QQQ), periodicidad D"
## [1] "Extrayendo QQQ..."
## [1] "QQQ extraído de Yahoo Finance..."
## [1] "Se terminó de extraer y procesar un total de 1 tickers desde las BD de Yahoo Finance..."
## [1] "Tickers procesados: QQQ"
rendimientos=Datos$tablaRendimientosCont$QQQ

La desviación estándar convencional:

sigma_fija=sd(rendimientos)
sigma_fija
## [1] 1.615079

La desviación estándar con suavizamiento exponencial con 0.95 y 0.98:

# Volatilidad con suavizamiento exponencial con lambda=0.95:
sigma95Lambda=rollEWSigma(rendimientos,0.95,250)

# Volatilidad con suavizamiento exponencial con lambda=0.98:
sigma98Lambda=rollEWSigma(rendimientos,0.98,250)

La desviación estándar GARCH:

#normal
sigmaGARCHT_norm=rollGARCH(rendimientos,model="sGARCH",LLF="norm",garchOrder=c(1,1),arma=c(0,0),include.mean=FALSE,ventana=250)
#t-studen
sigmaGARCHT_std=rollGARCH(rendimientos,model="sGARCH",LLF="std",garchOrder=c(1,1),arma=c(0,0),include.mean=FALSE,ventana=250)
#ged
sigmaGARCHT_ged=rollGARCH(rendimientos,model="sGARCH",LLF="ged",garchOrder=c(1,1),arma=c(0,0),include.mean=FALSE,ventana=250)

La desviación estándar GJR-GARCH:

#norm
spec <- ugarchspec(
  variance.model = list(model = "gjrGARCH", garchOrder = c(1, 1)),  
  mean.model = list(armaOrder = c(0, 0)),  
  distribution.model = "norm"  
)

window_size <- 250
n <- length(rendimientos)
volatility <- numeric(n - window_size + 1)
for (i in window_size:n) {
  sub_data <- rendimientos[(i - window_size + 1):i]
  fit <- ugarchfit(spec, sub_data)
  volatility[i - window_size + 1] <- sigma(fit)[length(sigma(fit))]
}
sigma_GJR_GARCHT_norm = volatility #rollgarch(spec = spec, data = rendimientos, width = 250, refit.every = 1)
#tstudent
spec <- ugarchspec(
  variance.model = list(model = "gjrGARCH", garchOrder = c(1, 1)),  
  mean.model = list(armaOrder = c(0, 0)),
  distribution.model = "std"  
)

window_size <- 250
n <- length(rendimientos)
volatility <- numeric(n - window_size + 1)
for (i in window_size:n) {
  sub_data <- rendimientos[(i - window_size + 1):i]
  fit <- ugarchfit(spec, sub_data)
  volatility[i - window_size + 1] <- sigma(fit)[length(sigma(fit))]
}
sigma_GJR_GARCHT_std = volatility
#sigma_GJR_GARCHT_std = rollgarch(spec = spec, data = rendimientos, width = 250, refit.every = 1)
#ged
spec <- ugarchspec(
  variance.model = list(model = "gjrGARCH", garchOrder = c(1, 1)),  
  mean.model = list(armaOrder = c(0, 0)),  
  distribution.model = "ged"  
)

window_size <- 250
n <- length(rendimientos)
volatility <- numeric(n - window_size + 1)
for (i in window_size:n) {
  sub_data <- rendimientos[(i - window_size + 1):i]
  fit <- ugarchfit(spec, sub_data)
  volatility[i - window_size + 1] <- sigma(fit)[length(sigma(fit))]
}
sigma_GJR_GARCHT_ged = volatility

#sigma_GJR_GARCHT_ged= rollgarch(spec = spec, data = rendimientos, width = 250, refit.every = 1)

Estos modelos se pueden contrastar contra la gráfica histórica:

# Gráfica comparativa:
figura2=plot_ly()%>%add_trace(x=~Date,
                              y=~QQQ,
                              data=Datos$tablaRendimientosCont,
                              type="scatter",
                              mode="lines",
                              name="Rendimientos QQQ")%>%
  add_trace(x=Datos$tablaRendimientosCont$Date,
            y=0+sigma_fija,
            type="scatter",
            mode="lines",
            name="Desviación estándar sup.")%>%
  add_trace(x=Datos$tablaRendimientosCont$Date,
            y=0-sigma_fija,
            type="scatter",
            mode="lines",
            name="Desviación estándar inf.")%>%
  add_trace(x=Datos$tablaRendimientosCont$Date,
            y=0+sigma95Lambda,
            type="scatter",
            mode="lines",
            name="Desviación estándar lambda 95 sup.")%>%
  add_trace(x=Datos$tablaRendimientosCont$Date,
            y=0+sigma98Lambda,
            type="scatter",
            mode="lines",
            name="Desviación estándar lambda 98 sup.")%>%
  add_trace(x=Datos$tablaRendimientosCont$Date,
            y=0-sigma95Lambda,
            type="scatter",
            mode="lines",
            name="Desviación estándar lambda 95 inf.")%>%
  add_trace(x=Datos$tablaRendimientosCont$Date,
            y=0-sigma98Lambda,
            type="scatter",
            mode="lines",
            name="Desviación estándar lambda 98 inf.")%>%
  add_trace(x=Datos$tablaRendimientosCont$Date,
            y=0+sigmaGARCHT_norm,
            type="scatter",
            mode="lines",
            name="Desviación estándar GARCH normal sup.")%>%
  add_trace(x=Datos$tablaRendimientosCont$Date,
            y=0-sigmaGARCHT_norm,
            type="scatter",
            mode="lines",
            name="Desviación estándar GARCH normal inf")%>%
  add_trace(x=Datos$tablaRendimientosCont$Date,
            y=0+sigmaGARCHT_std,
            type="scatter",
            mode="lines",
            name="Desviación estándar GARCH t-student sup.")%>%
  add_trace(x=Datos$tablaRendimientosCont$Date,
            y=0-sigmaGARCHT_std,
            type="scatter",
            mode="lines",
            name="Desviación estándar GARCH t-student inf")%>%
  add_trace(x=Datos$tablaRendimientosCont$Date,
            y=0+sigmaGARCHT_ged,
            type="scatter",
            mode="lines",
            name="Desviación estándar GARCH GED sup.")%>%
  add_trace(x=Datos$tablaRendimientosCont$Date,
            y=0-sigmaGARCHT_ged,
            type="scatter",
            mode="lines",
            name="Desviación estándar GARCH GED inf")%>%
  add_trace(x=Datos$tablaRendimientosCont$Date,
            y=0+c(rep(NA, length(Datos$tablaRendimientosCont$Date)-length(sigma_GJR_GARCHT_norm)), sigma_GJR_GARCHT_norm),
            type="scatter",
            mode="lines",
            name="Desviación estándar GJR GARCH normal sup.")%>%
  add_trace(x=Datos$tablaRendimientosCont$Date,
            y=0-c(rep(NA, length(Datos$tablaRendimientosCont$Date)-length(sigma_GJR_GARCHT_norm)), sigma_GJR_GARCHT_norm),
            type="scatter",
            mode="lines",
            name="Desviación estándar GJR GARCH normal inf")%>%
  add_trace(x=Datos$tablaRendimientosCont$Date,
            y=0+c(rep(NA, length(Datos$tablaRendimientosCont$Date)-length(sigma_GJR_GARCHT_std)), sigma_GJR_GARCHT_std),
            type="scatter",
            mode="lines",
            name="Desviación estándar GJR GARCH t-student sup.")%>%
  add_trace(x=Datos$tablaRendimientosCont$Date,
            y=0-c(rep(NA, length(Datos$tablaRendimientosCont$Date)-length(sigma_GJR_GARCHT_std)), sigma_GJR_GARCHT_std),
            type="scatter",
            mode="lines",
            name="Desviación estándar GJR GARCH t-student inf")%>%
  add_trace(x=Datos$tablaRendimientosCont$Date,
            y=0+c(rep(NA, length(Datos$tablaRendimientosCont$Date)-length(sigma_GJR_GARCHT_ged)), sigma_GJR_GARCHT_ged),
            type="scatter",
            mode="lines",
            name="Desviación estándar GJR GARCH GED sup.")%>%
  add_trace(x=Datos$tablaRendimientosCont$Date,
            y=0-c(rep(NA, length(Datos$tablaRendimientosCont$Date)-length(sigma_GJR_GARCHT_ged)), sigma_GJR_GARCHT_ged),
            type="scatter",
            mode="lines",
            name="Desviación estándar GJR GARCH GED inf")
figura2

Donde se visualiza que el mejor modelo es el GJR GARCH normal, que al igual que GJR t-student poseen comportamientos similares a los datos.

Tanto los resultados como la teoría muestran la importancia de implementar modelos que conserven información de movimientos “atípicos”, no solo de manera global como es el caso de la desviación estandar fija, sino de manera local como es el caso de los modelos GARCH. La implementación de estos permite no solo establecer intervalos de perdida que reducen la sobre o subestimación del fenómeno estudiado.

Por otro lado se realizó la introducción de los modelos GARCH asimétricos, los cuales son ampliamente utilizados en mercados financieros donde las caídas de precios tienden a generar más volatilidad que los aumentos.

Por ultimo se deja a discreción del usuario la elección del mejor modelo, ya que estos dependerán de los objetivos que se busquen lograr, teniendo en cuenta que:

Referencias